package com.cmc.cloud.cmclink.doc.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.lock.annotation.Lock4j;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cmc.cloud.cmclink.doc.api.document.emums.OptTpEnum;
import com.cmc.cloud.cmclink.doc.api.document.rep.AgentContactBaseDto;
import com.cmc.cloud.cmclink.doc.api.document.req.AgentContactReqDto;
import com.cmc.cloud.cmclink.doc.constants.OptConstants;
import com.cmc.cloud.cmclink.doc.constants.errorconstant.AgentContactErrorCodeConstants;
import com.cmc.cloud.cmclink.doc.convert.AgentContactConvert;
import com.cmc.cloud.cmclink.doc.entity.AgentContactDO;
import com.cmc.cloud.cmclink.doc.mapper.AgentContactMapper;
import com.cmc.cloud.cmclink.doc.service.AgentContactService;
import com.cmc.cloud.cmclink.doc.vo.*;
import com.cmes.framework.common.exception.util.ServiceExceptionUtil;
import com.cmes.framework.common.pojo.PageResult;
import com.cmes.framework.mybatis.core.query.LambdaQueryWrapperX;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;


/**
 * 航线进出口联系人信息 Service 实现类
 *
 * @author 招商轮船-管理员
 */
@Service
@Validated
public class AgentContactServiceImpl implements AgentContactService {

    @Resource
    private AgentContactMapper agentContactMapper;

    @Override
    @Lock4j(name = "agentContactUnique", keys = {"#createReqVO.getLaneCode", "#createReqVO.getAgentCode", "#createReqVO.getDatatype", "#createReqVO.getOptTp", "#createReqVO.getPortCode"})
    public void createAgentContact(AgentContactCreateReqVO createReqVO) {
        // 插入
        validateUniqueExists(createReqVO, null);
        AgentContactDO agentContactDO = BeanUtil.copyProperties(createReqVO, AgentContactDO.class);
        agentContactMapper.insert(agentContactDO);
    }

    @Override
    @Lock4j(name = "agentContactUnique", keys = {"#updateReqVO.getLaneCode", "#updateReqVO.getAgentCode", "#updateReqVO.getDatatype", "#updateReqVO.getOptTp", "#updateReqVO.getPortCode"})
    public void updateAgentContact(AgentContactUpdateReqVO updateReqVO) {
        // 校验存在
        validateAgentContactExists(updateReqVO.getId());
        validateUniqueExists(updateReqVO, updateReqVO.getId());
        // 更新
        AgentContactDO updateObj = BeanUtil.copyProperties(updateReqVO, AgentContactDO.class);
        agentContactMapper.updateById(updateObj);
    }

    private void validateUniqueExists(AgentContactBaseVO vo, Long id) {
        if (OptTpEnum.FCN_MCN.getValue().equals(vo.getOptTp()) || OptTpEnum.VOYAGE_NOTICE.getValue().equals(vo.getOptTp()) || OptTpEnum.CALCULATE_NOTICE.getValue().equals(vo.getOptTp())) {
            if (StringUtils.isEmpty(vo.getPortCode())) {
                throw ServiceExceptionUtil.exception(AgentContactErrorCodeConstants.AGENT_PORT_NOT_EXISTED);
            }
        }
        LambdaQueryWrapperX<AgentContactDO> baseQuery = new LambdaQueryWrapperX<AgentContactDO>()
                .eqIfPresent(AgentContactDO::getOptTp, vo.getOptTp())
                .eqIfPresent(AgentContactDO::getPortCode, vo.getPortCode())
                .eqIfPresent(AgentContactDO::getAgentCode, vo.getAgentCode())
                .eqIfPresent(AgentContactDO::getDatatype, vo.getDatatype());

        // 如果是更新操作，排除当前记录
        if (id != null) {
            baseQuery.ne(AgentContactDO::getId, id);
        }

        // 查询所有核心字段匹配的记录
        List<AgentContactDO> existList = agentContactMapper.selectList(baseQuery);
        if (existList.isEmpty()) {
            // 无匹配记录，直接通过校验
            return;
        }

        // 比对LaneCode，判断是否存在重复
        boolean isDuplicate = existList.stream().anyMatch(exist -> {
            // 新增数据的LaneCode
            String newLaneCode = vo.getLaneCode();
            // 数据库中已存在记录的LaneCode
            String existLaneCode = exist.getLaneCode();

            // 情况1：两者LaneCode都为空 → 重复
            if (StringUtils.isEmpty(newLaneCode) && StringUtils.isEmpty(existLaneCode)) {
                return true;
            }

            // 情况2：两者LaneCode都不为空且相等 → 重复
            if (StringUtils.isNotEmpty(newLaneCode) && newLaneCode.equals(existLaneCode)) {
                return true;
            }

            // 其他情况（一为空一不为空，或都不为空但不相等）→ 不重复
            return false;
        });


        // 根据OptTp类型抛出对应异常
        if (isDuplicate) {
            if (OptTpEnum.FCN_MCN.getValue().equals(vo.getOptTp())) {
                if (vo.getLaneCode() != null && !vo.getLaneCode().isEmpty()) {
                    throw ServiceExceptionUtil.exception(AgentContactErrorCodeConstants.AGENT_MCN_LANE_EXISTED, vo.getPortCode(), vo.getLaneCode());
                } else {
                    throw ServiceExceptionUtil.exception(AgentContactErrorCodeConstants.AGENT_MCN_PORT_EXISTED, vo.getPortCode());
                }
            } else if (OptTpEnum.VOYAGE_NOTICE.getValue().equals(vo.getOptTp())) {
                if (vo.getLaneCode() != null && !vo.getLaneCode().isEmpty()) {
                    throw ServiceExceptionUtil.exception(AgentContactErrorCodeConstants.AGENT_VOYAGE_NOTICE_LANE_EXISTED, vo.getPortCode(), vo.getLaneCode());
                } else {
                    throw ServiceExceptionUtil.exception(AgentContactErrorCodeConstants.AGENT_VOYAGE_NOTICE_PORT_EXISTED, vo.getPortCode());
                }
            } else if (OptTpEnum.CALCULATE_NOTICE.getValue().equals(vo.getOptTp())) {
                if (vo.getLaneCode() != null && !vo.getLaneCode().isEmpty()) {
                    throw ServiceExceptionUtil.exception(AgentContactErrorCodeConstants.AGENT_CALCULATE_NOTICE_LANE_EXISTED, vo.getPortCode(), vo.getLaneCode());
                } else {
                    throw ServiceExceptionUtil.exception(AgentContactErrorCodeConstants.AGENT_CALCULATE_NOTICE_PORT_EXISTED, vo.getPortCode());
                }
            } else {
                throw ServiceExceptionUtil.exception(AgentContactErrorCodeConstants.AGENT_CONTACT_EXISTED);
            }
        }
    }


    @Override
    public void deleteAgentContact(Long id) {
        // 校验存在
        validateAgentContactExists(id);
        // 删除
        agentContactMapper.deleteById(id);
    }

    private void validateAgentContactExists(Long id) {
        if (agentContactMapper.selectById(id) == null) {
            throw ServiceExceptionUtil.exception(AgentContactErrorCodeConstants.AGENT_CONTACT_NOT_EXISTS);
        }
    }

    @Override
    public AgentContactDO getAgentContact(Long id) {
        return agentContactMapper.selectById(id);
    }

    @Override
    public List<AgentContactDO> getAgentContactList(Collection<Long> ids) {
        return agentContactMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<AgentContactDO> getAgentContactPage(AgentContactPageReqVO reqVO) {
        LambdaQueryWrapper<AgentContactDO> queryWrapper = new LambdaQueryWrapperX<AgentContactDO>().eqIfPresent(AgentContactDO::getOptTp, reqVO.getOptTp()).eqIfPresent(AgentContactDO::getDatatype, reqVO.getDatatype());
        if (StringUtils.isNotEmpty(reqVO.getKeyWord())) {
            queryWrapper.and(wrapper -> wrapper.like(AgentContactDO::getPortCode, reqVO.getKeyWord()).or().like(AgentContactDO::getLaneCode, reqVO.getKeyWord()));
        }
        queryWrapper.orderByDesc(AgentContactDO::getCreateTime);
        PageResult<AgentContactDO> result = agentContactMapper.selectPage(reqVO, queryWrapper);
        return result;
    }

    @Override
    public PageResult<AgentContactDO> personPage(AgentContactPageReqVO pageReqVO) {
        LambdaQueryWrapperX<AgentContactDO> queryWrapper = new LambdaQueryWrapperX<AgentContactDO>();
        queryWrapper.eqIfPresent(AgentContactDO::getDatatype, pageReqVO.getDatatype()).eqIfPresent(AgentContactDO::getLaneCode, pageReqVO.getLaneCode()).eqIfPresent(AgentContactDO::getPortCode, pageReqVO.getPortCode()).in(AgentContactDO::getOptTp, Arrays.asList(OptConstants.EXPORT_CONTACT, OptConstants.IMPORT_CONTACT));
        queryWrapper.orderByDesc(AgentContactDO::getCreateTime);
        PageResult<AgentContactDO> result = agentContactMapper.selectPage(pageReqVO, queryWrapper);
        return result;
    }

    @Override
    public PageResult<AgentContactDO> remarkPage(AgentContactPageReqVO pageReqVO) {
        LambdaQueryWrapperX<AgentContactDO> queryWrapper = new LambdaQueryWrapperX<AgentContactDO>();
        queryWrapper.eqIfPresent(AgentContactDO::getDatatype, pageReqVO.getDatatype()).eqIfPresent(AgentContactDO::getPortCode, pageReqVO.getPortCode());
        queryWrapper.in(AgentContactDO::getOptTp, Arrays.asList(OptConstants.EXPORT_REMARK, OptConstants.IMPORT_REMARK));
        queryWrapper.orderByDesc(AgentContactDO::getCreateTime);
        return agentContactMapper.selectPage(pageReqVO, queryWrapper);
    }

    @Override
    public List<AgentContactExcelRespVO> exportExcel(AgentContactReqVO agentContactReqVO) {
        LambdaQueryWrapperX<AgentContactDO> queryWrapper = new LambdaQueryWrapperX<AgentContactDO>();
        queryWrapper.eqIfPresent(AgentContactDO::getDatatype, agentContactReqVO.getDatatype()).eqIfPresent(AgentContactDO::getLaneCode, agentContactReqVO.getLaneCode()).eqIfPresent(AgentContactDO::getPortCode, agentContactReqVO.getPortCode()).in(AgentContactDO::getOptTp, Arrays.asList(OptConstants.EXPORT_CONTACT, OptConstants.IMPORT_CONTACT));
        queryWrapper.orderByDesc(AgentContactDO::getCreateTime);
        List<AgentContactDO> agentContactDOList = agentContactMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(agentContactDOList)) {
            return null;
        }
        List<AgentContactExcelRespVO> result = AgentContactConvert.INSTANCE.convertAgentContactExcelRespVO(agentContactDOList);
        return result;
    }

    @Override
    public List<AgentContactBaseDto> agentContact(AgentContactReqDto agentContactReqDto) {
        LambdaQueryWrapperX<AgentContactDO> queryWrapper = new LambdaQueryWrapperX<AgentContactDO>();
        queryWrapper.eqIfPresent(AgentContactDO::getDatatype, agentContactReqDto.getDatatype())
                .eqIfPresent(AgentContactDO::getPortCode, agentContactReqDto.getPortCode())
                .in(AgentContactDO::getOptTp, Arrays.asList(OptConstants.EXPORT_CONTACT, OptConstants.IMPORT_CONTACT));
        if (CollectionUtils.isNotEmpty(agentContactReqDto.getLaneCodeS())) {
            queryWrapper.in(AgentContactDO::getLaneCode, agentContactReqDto.getLaneCodeS());
        }
        queryWrapper.orderByDesc(AgentContactDO::getCreateTime);
        List<AgentContactDO> agentContactDOList = agentContactMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(agentContactDOList)) {
            return null;
        }
        List<AgentContactBaseDto> agentContactBaseDtoList = AgentContactConvert.INSTANCE.convertList(agentContactDOList);
        return agentContactBaseDtoList;
    }
}
